"""
get classifer result
"""
import os
from commonfunc import *

class ClassiferResultParserError(Exception):pass
class FormatNotMatchError(ClassiferResultParserError):pass
class FileNotExistError(ClassiferResultParserError):pass
class ParameterError(ClassiferResultParserError):pass
class FileFormatError(ClassiferResultParserError):pass

def getGlobalResultOnTrain(rfilename):
    """
    get the global result of a run
    case 1: there are words such as result on train data
    case 2: the result is related to each item
    start with "=== Error on training data ==="
    end with the line start with "Weighted Avg."
    """
    if os.path.isfile(rfilename) == False:
        raise FileNotExistError("FileNotExist")
    f = open(rfilename)
    lines = f.readlines()
    f.close()

    dic = {}
    dic['detail'] = {}
    trainindex = getLineIndexBeginWith(lines,"=== Error on training data ===")
    #here wrong , do not get the right index here
    detailindex = getLineHas(lines,"TP Rate",trainindex)
    if detailindex == -1:
        raise FileFormatError("can not locate the line with TP Rate")
        

    #the next non empty line is the item desp
    curindex = detailindex + 1
    while curindex < len(lines):
        if lines[curindex] == "\n" or lines[curindex] == "":
            curindex += 1
            continue
        
        if lines[curindex].startswith("Weighted Avg."):
            items = getLineItems(lines[curindex])
            dic['all'] = {}
            dic['all']['tp'] = float(items[2])
            dic['all']['fp'] = float(items[3])
            dic['all']['precision'] = float(items[4])
            dic['all']['recall'] = float(items[5])
            dic['all']['fm'] = float(items[6])
            break
        
        items = getLineItems(lines[curindex])
        dic['detail'][items[6]] = {}
        dic['detail'][items[6]]['tp'] = float(items[0])
        dic['detail'][items[6]]['fp'] = float(items[1])
        dic['detail'][items[6]]['precision'] = float(items[2])
        dic['detail'][items[6]]['recall'] = float(items[3])
        dic['detail'][items[6]]['fm'] = float(items[4])
        curindex += 1
   
    return dic       
    
def getGlobalResultOnTest(rfilename):
    """
    get the global result of a run
    case 1: there are words such as result on test data
    case 2: the result is related to each item
    """
    if os.path.isfile(rfilename) == False:
        raise FileNotExistError("FileNotExist : "+rfilename)
    f = open(rfilename)
    lines = f.readlines()
    f.close()

    dic = {}
    dic['detail'] = {}
    trainindex = getLineIndexBeginWith(lines,"=== Error on test data ===")
    detailindex = getLineHas(lines,"TP Rate",trainindex)

    #the next non empty line is the item desp
    curindex = detailindex + 1
    while curindex < len(lines):
        if lines[curindex] == "\n" or lines[curindex] == "":
            curindex += 1
            continue
        
        if lines[curindex].startswith("Weighted Avg."):
            items = getLineItems(lines[curindex])
            dic['all'] = {}
            dic['all']['tp'] = float(items[2])
            dic['all']['fp'] = float(items[3])
            dic['all']['precision'] = float(items[4])
            dic['all']['recall'] = float(items[5])
            dic['all']['fm'] = float(items[6])
            break
        
        items = getLineItems(lines[curindex])
        dic['detail'][items[6]] = {}
        dic['detail'][items[6]]['tp'] = float(items[0])
        dic['detail'][items[6]]['fp'] = float(items[1])
        dic['detail'][items[6]]['precision'] = float(items[2])
        dic['detail'][items[6]]['recall'] = float(items[3])
        dic['detail'][items[6]]['fm'] = float(items[4])
        curindex += 1
   
    return dic


def getDetailResult(rfilename):
    """
    get the detail result of a run,with -p -distribute option
    if not the case,raise Exception
    the orginal detail distribution.py
    """
    if os.path.isfile(rfilename) == False:
        raise FileNotExistError("FileNotExist"+rfilename)
    result = {}
    f = open(rfilename)
    lines = f.readlines()
    f.close()

    for line in lines:
        ws = getLineItems(line," ")
        if len(ws) == 0:
            continue
        if ws[0][0].isdigit():
            dic = {}
            dic['index'] = int(ws[0])
            dic['trueclass'] = int(ws[1][ws[1].index(':')+1:len(ws[1])])
            dic['predictclass'] = int(ws[2][ws[2].index(':')+1:len(ws[2])])
            dis = {}
            ps = ws[len(ws)-1].split(',')
            for i in range(len(ps)):
                if ps[i].startswith('*'):
                    dis[i] = float(ps[i][1:len(ps[i])])
                else:
                    dis[i] = float(ps[i])
            dic['dis'] = dis
            result[int(ws[0])] = dic

    return result

def writeDetailResult(rdic,rfilename):
    """
    write the detail result dic in memory to disc
    assumption : the class label of weka is the true label+1,which means the the label is number like
    the dis has three float number after the point
    """
    head = """

=== Predictions on test data ===

 inst#     actual  predicted error distribution ()"""
    f = open(rfilename,"w")
    print>>f,head
    for k in rdic.keys():
        print>>f,"% 6d" %k,
        print>>f,"% 11s" % str(rdic[k]['trueclass']+1)+":"+str(rdic[k]['trueclass']),
        print>>f,"% 11s" % str(rdic[k]['predictclass']+1)+":"+str(rdic[k]['predictclass']),
        if rdic[k]['trueclass'] != rdic[k]['predictclass']:
            print>>f,"% 4s" % "+   ",
        else:
            print>>f,"% 4s" % "    ",
        tmpstr = ""
        for i in range(len(rdic[k]['dis'])):
            if i == rdic[k]['predictclass']:
                tmpstr += ("*"+str(rdic[k]['dis'][i])+",")
            else:
                tmpstr += str(rdic[k]['dis'][i])+","
        print>>f,tmpstr[0:len(tmpstr)-1]
    f.close()
    
    
    
def getCrossMatrix(rfilename,istr):
    """
    for multiclass problem
    get the cross validate from the total resultfile,not static from detail

    === Error on training data ===
    ...
    === Confusion Matrix ===
    ...
    identifed by str '<--'
    
    @param rfilename
    @param istr : whether or not matrix on trfile ,not in detail file
    @return dic from truetype to predicttype to the count
    """
    f = open(rfilename)
    lines = f.readlines()
    f.close()

    curindex = 0
    while lines[curindex].find("<--") == -1:
        curindex += 1
    
    if istr == False:
        curindex += 1
        while lines[curindex].find("<--") == -1:
            curindex += 1

    # get the line to begin with
    # 1 analyse the first line to get total number of class
    items = getLineItems(lines[curindex]," ")
    cs = []
    for i in items:
        if i == "<--":
            break
        cs.append(i)
        
    # 2 read corresponse line to get the cross matrix
    dic = {}
    for i in range(len(cs)):
        dic[i] = {}
        for j in range(len(cs)):
            dic[i][j] = 0
            
    ts = []
    for i in range(len(cs)):
        cmnums = getLineItems(lines[curindex+i+1]," ")
        ts.append(cmnums[len(cmnums)-1])
        for j in range(len(cs)):
            dic[i][j] = int(cmnums[j])
    
    # 3 replace with the real class name
    result = {}
    for i in range(len(cs)):
        result[ts[i]] = {}

    for i in range(len(cs)):
        for j in range(len(cs)):
            result[ts[i]][ts[j]] = dic[i][j]

    return result

    
def getCrossMatixDetail(rfilename):
    """
    for multiclass problem
    get the cross validate from static from detail
    @param rfilename
    """
    rdic = getDetailResult(rfilename)
    lables = range(len(rdic[1]['dis']))
    true2pre = {}
    
    for k in lables:
        true2pre[k] = {}
        for j in lables:
            true2pre[k][j] = 0
            
    for k in rdic.keys():
        true2pre[rdic[k]['trueclass']][rdic[k]['predictclass']] += 1
        
    return true2pre
    
